require "fileutils"

class Command
  attr_reader :description
  
  def initialize(description)
    @description = description
  end
  
  def execute
    
  end
end

class CreateFile < Command
  def initialize(path, contents)
    super("Create file: #{path}")
    @path, @contents = path, contents
  end
  
  def execute
    f = File.open(@path, "w")
    f.write(@contents)
    f.close
  end
  
  def unexecute
    File.delete(@path)
  end
end

class DeleteFile < Command
  def initialize(path)
    super("Delete file: #{path}")
    @path = path
  end
  
  def execute
    if File.exists?(@path)
      @contents = File.read(@path)
    end
    f = File.delete(@path)
  end
  
  def unexecute
    if @contents
      f = File.open(@path, "w")
      f.write(@contents)
      f.close
    end
  end
end

class CopyFile < Command
  def initialize(source, target)
    super("Copy file: #{source} to #{target}")
    @source, @target = source, target
  end
  
  def execute
    if File.exists?(@target)
      @already_exists = true
      @contents = File.read(@target)
    end
    FileUtils.copy(@source, @target)
  end
  
  def unexecute
    if @already_exists
      f = File.open(@target, "w")
      f.write(@contents)
      f.close
    else
      File.delete(@target)
    end
  end
end

class CompositeCommand < Command
  def initialize
    @commands = []
  end
  
  def add_command(cmd)
    @commands << cmd
  end
  
  def execute
    @commands.each { |cmd| cmd.execute }
  end
  
  def unexecute
    @commands.reverse.each { |cmd| cmd.unexecute }
  end
  
  def description
    @commands.inject("") { |description, cmd| description += cmd.description }
  end
end

cmds = CompositeCommand.new

cmds.add_command(CreateFile.new("file.txt", "Hello world!\n"))
cmds.add_command(CopyFile.new("file.txt", "file.bak.txt"))
cmds.add_command(DeleteFile.new("file.txt"))

cmds.execute
puts "Sleeping..."
sleep(10)
cmds.unexecute